package com.common.app.base

import android.Manifest
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import android.net.Uri
import android.text.TextUtils
import android.widget.ImageView
import androidx.activity.result.ActivityResultLauncher
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.viewbinding.ViewBinding
import com.bumptech.glide.Glide
import com.bumptech.glide.request.target.CustomTarget
import com.bumptech.glide.request.transition.Transition
import com.common.app.R
import com.common.app.utls.pictureselect.GlideEngine
import com.common.app.utls.pictureselect.ImageLoaderUtils
import com.common.base.app.viewmodel.BaseViewModel
import com.luck.picture.lib.animators.AnimationType
import com.luck.picture.lib.basic.PictureSelector
import com.luck.picture.lib.config.*
import com.luck.picture.lib.dialog.RemindDialog
import com.luck.picture.lib.engine.CompressFileEngine
import com.luck.picture.lib.engine.CropFileEngine
import com.luck.picture.lib.engine.UriToFileTransformEngine
import com.luck.picture.lib.entity.LocalMedia
import com.luck.picture.lib.interfaces.*
import com.luck.picture.lib.language.LanguageConfig
import com.luck.picture.lib.permissions.PermissionConfig
import com.luck.picture.lib.permissions.PermissionUtil
import com.luck.picture.lib.style.BottomNavBarStyle
import com.luck.picture.lib.style.PictureSelectorStyle
import com.luck.picture.lib.style.SelectMainStyle
import com.luck.picture.lib.style.TitleBarStyle
import com.luck.picture.lib.utils.*
import com.yalantis.ucrop.UCrop
import com.yalantis.ucrop.UCropImageEngine
import top.zibin.luban.Luban
import top.zibin.luban.OnNewCompressListener
import java.io.File

/**
 * 作者：sosou
 * <p>
 * 版本：1.0
 * <p>
 * 创建日期：2022/8/19
 * <p>
 * 描述：图片选择
 * <p>
 * 修订历史：
 */
abstract class AppPictureSelectionFragment<VB : ViewBinding, VM : BaseViewModel> : AppFragment<VB, VM>() {

    var selectorStyle: PictureSelectorStyle? = null

    /**
     * 1:1
     */
    var aspect_ratio_x = 1f

    /**
     * 1:1
     */
    var aspect_ratio_y: kotlin.Float = 1f

    /**
     * 裁剪框or图片拖动
     */
    var freeStyleCropEnabled = false

    /**
     * 是否显示裁剪菜单栏
     */
    var hideBottomControls = false

    /**
     * 相机通用配置
     *
     * @param launcher
     */
    open fun openCamera(launcher: ActivityResultLauncher<Intent?>?) {
        // 单独拍照
        val cameraModel = PictureSelector.create(this)
            .openCamera(SelectMimeType.ofImage())
            .setCameraInterceptListener(null)
            .setRecordAudioInterceptListener(null)
            .setCropEngine(ImageFileCropEngine()) //                .setCompressEngine(new ImageFileCompressEngine())//压缩
            .setAddBitmapWatermarkListener(null) //水印
            .setVideoThumbnailListener(null) //视频缩略图
            .setLanguage(LanguageConfig.UNKNOWN_LANGUAGE)
            .setSandboxFileEngine(MeSandboxFileEngine())
            .isOriginalControl(false)
            .setPermissionDescriptionListener(null) //权限说明
            .setOutputAudioDir(getSandboxPath())
        cameraModel.forResultActivity(launcher)
    }

    /**
     * 配制UCrop，可根据需求自我扩展
     *
     * @return
     */
    open fun buildOptions(): UCrop.Options {
        val options = UCrop.Options()
        options.setHideBottomControls(hideBottomControls)
        options.setFreeStyleCropEnabled(freeStyleCropEnabled)
        options.setShowCropFrame(true)
        options.setShowCropGrid(true)
        options.setCircleDimmedLayer(false) //圆形头像裁剪模式
        options.withAspectRatio(aspect_ratio_x, aspect_ratio_y)
        options.setCropOutputPathDir(getSandboxPath())
        options.isCropDragSmoothToCenter(false)
        options.isUseCustomLoaderBitmap(true)
        options.setSkipCropMimeType("")
        options.isForbidCropGifWebp(false)
        options.isForbidSkipMultipleCrop(false)
        options.setMaxScaleMultiplier(100f)

        selectorStyle?.let {
            if (it.selectMainStyle.statusBarColor != 0) {
                val mainStyle = it.selectMainStyle
                val isDarkStatusBarBlack = mainStyle.isDarkStatusBarBlack
                val statusBarColor = mainStyle.statusBarColor
                options.isDarkStatusBarBlack(isDarkStatusBarBlack)
                if (StyleUtils.checkStyleValidity(statusBarColor)) {
                    options.setStatusBarColor(statusBarColor)
                    options.setToolbarColor(statusBarColor)
                } else {
                    options.setStatusBarColor(ContextCompat.getColor(requireActivity(), R.color.ps_color_grey))
                    options.setToolbarColor(ContextCompat.getColor(requireActivity(), R.color.ps_color_grey))
                }
                val titleBarStyle = it.titleBarStyle
                if (StyleUtils.checkStyleValidity(titleBarStyle.titleTextColor)) {
                    options.setToolbarWidgetColor(titleBarStyle.titleTextColor)
                } else {
                    options.setToolbarWidgetColor(
                        ContextCompat.getColor(
                            requireActivity(),
                            R.color.ps_color_white
                        )
                    )
                }
            } else {
                options.setStatusBarColor(ContextCompat.getColor(requireActivity(), R.color.ps_color_grey))
                options.setToolbarColor(ContextCompat.getColor(requireActivity(), R.color.ps_color_grey))
                options.setToolbarWidgetColor(ContextCompat.getColor(requireActivity(), R.color.ps_color_white))
            }
        }.let {
            options.setStatusBarColor(ContextCompat.getColor(requireActivity(), R.color.ps_color_grey))
            options.setToolbarColor(ContextCompat.getColor(requireActivity(), R.color.ps_color_grey))
            options.setToolbarWidgetColor(ContextCompat.getColor(requireActivity(), R.color.ps_color_white))
        }
        return options
    }

    /**
     * 自定义裁剪
     */
    inner class ImageFileCropEngine : CropFileEngine {

        override fun onStartCrop(
            fragment: Fragment,
            srcUri: Uri,
            destinationUri: Uri,
            dataSource: ArrayList<String>,
            requestCode: Int
        ) {
            val options: UCrop.Options = buildOptions()
            val uCrop = UCrop.of(srcUri, destinationUri, dataSource)
            uCrop.withOptions(options)
            uCrop.setImageEngine(object : UCropImageEngine {
                override fun loadImage(context: Context, url: String, imageView: ImageView) {
                    if (!ImageLoaderUtils.assertValidRequest(context)) {
                        return
                    }
                    Glide.with(context).load(url).override(180, 180).into(imageView)
                }

                override fun loadImage(
                    context: Context,
                    url: Uri,
                    maxWidth: Int,
                    maxHeight: Int,
                    call: UCropImageEngine.OnCallbackListener<Bitmap>?
                ) {
                    if (!ImageLoaderUtils.assertValidRequest(context)) {
                        return
                    }
                    Glide.with(context).asBitmap().override(maxWidth, maxHeight).load(url)
                        .into(object : CustomTarget<Bitmap>() {
                            override fun onResourceReady(
                                resource: Bitmap,
                                transition: Transition<in Bitmap>?
                            ) {
                                call?.onCall(resource)
                            }

                            override fun onLoadFailed(errorDrawable: Drawable?) {
                                call?.onCall(null)
                            }

                            override fun onLoadCleared(placeholder: Drawable?) {}
                        })
                }
            })
            fragment.activity?.let { uCrop.start(it, fragment, requestCode) }
        }
    }

    /**
     * 自定义压缩
     */
    class ImageFileCompressEngine : CompressFileEngine {
        override fun onStartCompress(
            context: Context,
            source: ArrayList<Uri>,
            call: OnKeyValueResultCallbackListener?
        ) {
            Luban.with(context).load(source).ignoreBy(100).setRenameListener { filePath ->
                val indexOf = filePath.lastIndexOf(".")
                val postfix = if (indexOf != -1) filePath.substring(indexOf) else ".jpg"
                DateUtils.getCreateFileName("CMP_") + postfix
            }.setCompressListener(object : OnNewCompressListener {
                override fun onStart() {}
                override fun onSuccess(source: String, compressFile: File) {
                    call?.onCallback(source, compressFile.absolutePath)
                }

                override fun onError(source: String, e: Throwable) {
                    call?.onCallback(source, null)
                }
            }).launch()
        }
    }

    /**
     * 自定义沙盒文件处理
     */
    class MeSandboxFileEngine : UriToFileTransformEngine {
        override fun onUriToFileAsyncTransform(
            context: Context,
            srcPath: String,
            mineType: String,
            call: OnKeyValueResultCallbackListener?
        ) {
            call?.onCallback(
                srcPath,
                SandboxTransformUtils.copyPathToSandbox(context, srcPath, mineType)
            )
        }
    }

    /**
     * 拦截自定义提示
     */
    class MeOnSelectLimitTipsListener : OnSelectLimitTipsListener {
        override fun onSelectLimitTips(
            context: Context?,
            media: LocalMedia?,
            config: SelectorConfig?,
            limitType: Int
        ): Boolean {
            if (limitType == SelectLimitType.SELECT_NOT_SUPPORT_SELECT_LIMIT) {
                ToastUtils.showToast(context, "暂不支持的选择类型")
                return true
            }
            return false
        }
    }

    /**
     * 自定义编辑
     */
    private class MeOnMediaEditInterceptListener(
        private val outputCropPath: String,
        private val options: UCrop.Options
    ) :
        OnMediaEditInterceptListener {
        override fun onStartMediaEdit(
            fragment: Fragment,
            currentLocalMedia: LocalMedia,
            requestCode: Int
        ) {
            val currentEditPath = currentLocalMedia.availablePath
            val inputUri =
                if (PictureMimeType.isContent(currentEditPath)) Uri.parse(currentEditPath) else Uri.fromFile(
                    File(currentEditPath)
                )
            val destinationUri = Uri.fromFile(
                File(outputCropPath, DateUtils.getCreateFileName("CROP_") + ".jpeg")
            )
            val uCrop = UCrop.of<Any>(inputUri, destinationUri)
            options.setHideBottomControls(false)
            uCrop.withOptions(options)
            fragment.activity?.let { uCrop.startEdit(it, fragment, requestCode) }
        }
    }

    /**
     * 权限拒绝后回调
     */
    class MeOnPermissionDeniedListener : OnPermissionDeniedListener {
        override fun onDenied(
            fragment: Fragment, permissionArray: Array<String>,
            requestCode: Int, call: OnCallbackListener<Boolean>
        ) {
            val tips: String
            tips = if (TextUtils.equals(permissionArray[0], PermissionConfig.CAMERA[0])) {
                "缺少相机权限\n可能会导致不能使用摄像头功能"
            } else if (TextUtils.equals(permissionArray[0], Manifest.permission.RECORD_AUDIO)) {
                "缺少录音权限\n访问您设备上的音频、媒体内容和文件"
            } else {
                "缺少存储权限\n访问您设备上的照片、媒体内容和文件"
            }
            val dialog = RemindDialog.buildDialog(fragment.context, tips)
            dialog.setButtonText("去设置")
            dialog.setButtonTextColor(-0x828201)
            dialog.setContentTextColor(-0xcccccd)
            dialog.setOnDialogClickListener {
                PermissionUtil.goIntentSetting(fragment, requestCode)
                dialog.dismiss()
            }
            dialog.show()
        }
    }

    /**
     * 创建自定义输出目录
     *
     * @return
     */
    open fun getSandboxPath(): String {
        val externalFilesDir = requireActivity().getExternalFilesDir("")
        val customFile = File(externalFilesDir?.absolutePath, "Sandbox")
        if (!customFile.exists()) {
            customFile.mkdirs()
        }
        return customFile.absolutePath + File.separator
    }

    /**
     * 初始化风格
     */
    open fun initPictureStyle() {
        aspect_ratio_x = 1f
        aspect_ratio_y = 1f
        freeStyleCropEnabled = true
        selectorStyle = PictureSelectorStyle()

        // 主体风格
        val numberSelectMainStyle = SelectMainStyle()
        numberSelectMainStyle.isSelectNumberStyle = true
        numberSelectMainStyle.isPreviewSelectNumberStyle = false
        numberSelectMainStyle.isPreviewDisplaySelectGallery = true
        numberSelectMainStyle.selectBackground = R.drawable.ps_default_num_selector
        numberSelectMainStyle.previewSelectBackground = R.drawable.ps_preview_checkbox_selector
        numberSelectMainStyle.selectNormalBackgroundResources =
            R.drawable.ps_select_complete_normal_bg
        numberSelectMainStyle.selectNormalTextColor =
            ContextCompat.getColor(requireActivity(), R.color.ps_color_53575e)
        numberSelectMainStyle.selectNormalText = getString(R.string.ps_send)
        numberSelectMainStyle.adapterPreviewGalleryBackgroundResource =
            R.drawable.ps_preview_gallery_bg
        numberSelectMainStyle.adapterPreviewGalleryItemSize =
            DensityUtil.dip2px(requireActivity(), 52f)
        numberSelectMainStyle.previewSelectText = getString(R.string.ps_select)
        numberSelectMainStyle.previewSelectTextSize = 14
        numberSelectMainStyle.previewSelectTextColor =
            ContextCompat.getColor(requireActivity(), R.color.ps_color_white)
        numberSelectMainStyle.previewSelectMarginRight =
            DensityUtil.dip2px(requireActivity(), 6f)
        numberSelectMainStyle.selectBackgroundResources = R.drawable.ps_select_complete_bg
        numberSelectMainStyle.selectText = getString(R.string.ps_send_num)
        numberSelectMainStyle.selectTextColor = ContextCompat.getColor(requireActivity(), R.color.ps_color_white)
        numberSelectMainStyle.mainListBackgroundColor =
            ContextCompat.getColor(requireActivity(), R.color.ps_color_black)
        numberSelectMainStyle.isCompleteSelectRelativeTop = true
        numberSelectMainStyle.isPreviewSelectRelativeBottom = true
        numberSelectMainStyle.isAdapterItemIncludeEdge = false

        // 头部TitleBar 风格
        val numberTitleBarStyle = TitleBarStyle()
        numberTitleBarStyle.isHideCancelButton = true
        numberTitleBarStyle.isAlbumTitleRelativeLeft = true
        numberTitleBarStyle.titleAlbumBackgroundResource = R.drawable.ps_album_bg
        numberTitleBarStyle.titleDrawableRightResource = R.drawable.ps_ic_grey_arrow
        numberTitleBarStyle.previewTitleLeftBackResource = R.drawable.ps_ic_normal_back

        // 底部NavBar 风格
        val numberBottomNavBarStyle = BottomNavBarStyle()
        numberBottomNavBarStyle.bottomPreviewNarBarBackgroundColor =
            ContextCompat.getColor(requireActivity(), R.color.ps_color_half_grey)
        numberBottomNavBarStyle.bottomPreviewNormalText = getString(R.string.ps_preview)
        numberBottomNavBarStyle.bottomPreviewNormalTextColor =
            ContextCompat.getColor(requireActivity(), R.color.ps_color_9b)
        numberBottomNavBarStyle.bottomPreviewNormalTextSize = 16
        numberBottomNavBarStyle.isCompleteCountTips = false
        numberBottomNavBarStyle.bottomPreviewSelectText = getString(R.string.ps_preview_num)
        numberBottomNavBarStyle.bottomPreviewSelectTextColor =
            ContextCompat.getColor(requireActivity(), R.color.ps_color_white)
        selectorStyle?.titleBarStyle = numberTitleBarStyle
        selectorStyle?.bottomBarStyle = numberBottomNavBarStyle
        selectorStyle?.selectMainStyle = numberSelectMainStyle
    }


    /**
     * 相册选择通配
     *
     * @param single
     */
    open fun selectFromAlbum(
        single: Boolean,
        launcher: ActivityResultLauncher<Intent?>?,
        maxSelectNum: Int
    ) {
        // 进入相册
        val selectionModel = PictureSelector.create(this)
            .openGallery(SelectMimeType.ofImage()) // 全部.PictureMimeType.ofAll()、图片.ofImage()、视频.ofVideo()、音频.ofAudio()
            .setSelectorUIStyle(selectorStyle)
            .setImageEngine(GlideEngine.createGlideEngine())
            .setCropEngine(ImageFileCropEngine()) //                .setCompressEngine(new ImageFileCompressEngine())//压缩
            .setSandboxFileEngine(MeSandboxFileEngine())
            .setCameraInterceptListener(null) //自定义相机
            .setRecordAudioInterceptListener(null) //录音
            .setSelectLimitTipsListener(MeOnSelectLimitTipsListener())
            .setEditMediaInterceptListener(
                MeOnMediaEditInterceptListener(
                    getSandboxPath(),
                    buildOptions()
                )
            )
            .setPermissionDescriptionListener(null) //权限说明
            .setPreviewInterceptListener(null) //自定义预览
            .setPermissionDeniedListener(MeOnPermissionDeniedListener())
            .setAddBitmapWatermarkListener(null) //水印
            .setVideoThumbnailListener(null) //视频缩略图
            .setInjectLayoutResourceListener(null) //自定义布局
            .setSelectionMode(if (single) SelectModeConfig.SINGLE else SelectModeConfig.MULTIPLE) //单选
            .setLanguage(LanguageConfig.UNKNOWN_LANGUAGE)
            .setQuerySortOrder("") //排序
            .setOutputCameraDir(getSandboxPath())
            .setOutputAudioDir(getSandboxPath())
            .setQuerySandboxDir(getSandboxPath())
            .isDisplayTimeAxis(true)
            .isOnlyObtainSandboxDir(false)
            .isPageStrategy(true)
            .isOriginalControl(false)
            .isDisplayCamera(true)
            .isOpenClickSound(false)
            .setSkipCropMimeType("")
            .isFastSlidingSelect(true) //.setOutputCameraImageFileName("luck.jpeg")
            //.setOutputCameraVideoFileName("luck.mp4")//视频输出文件名
            .isWithSelectVideoImage(true)
            .isPreviewFullScreenMode(true)
            .isPreviewZoomEffect(true)
            .isPreviewImage(true)
            .isPreviewVideo(true)
            .isPreviewAudio(true) //.setQueryOnlyMimeType(PictureMimeType.ofGIF())
            .isMaxSelectEnabledMask(true)
            .isDirectReturnSingle(false)
            .setMaxSelectNum(maxSelectNum)
            .setMaxVideoSelectNum(1)
            .setRecyclerAnimationMode(-1)
            .isGif(false)
            .setSelectedData(java.util.ArrayList<LocalMedia>())
        selectionModel.forResult(launcher)
    }


    /**
     * 相册选择通配
     *
     * @param single
     */
    open fun selectFromAlbumHasAudio(
        maxVideoSelectNum: Int,
        single: Boolean,
        launcher: ActivityResultLauncher<Intent?>?,
        maxSelectNum: Int
    ) {
        // 进入相册
        val selectionModel = PictureSelector.create(this)
            .openGallery(SelectMimeType.ofAll()) // 全部.PictureMimeType.ofAll()、图片.ofImage()、视频.ofVideo()、音频.ofAudio()
            .setSelectorUIStyle(selectorStyle)
            .setImageEngine(GlideEngine.createGlideEngine())
            .setCropEngine(ImageFileCropEngine()) //                .setCompressEngine(new ImageFileCompressEngine())//压缩
            .setSandboxFileEngine(MeSandboxFileEngine())
            .setCameraInterceptListener(null) //自定义相机
            .setRecordAudioInterceptListener(null) //录音
            .setSelectLimitTipsListener(MeOnSelectLimitTipsListener())
            .setEditMediaInterceptListener(
                MeOnMediaEditInterceptListener(
                    getSandboxPath(),
                    buildOptions()
                )
            )
            .setPermissionDescriptionListener(null) //权限说明
            .setPreviewInterceptListener(null) //自定义预览
            .setPermissionDeniedListener(MeOnPermissionDeniedListener())
            .setAddBitmapWatermarkListener(null) //水印
            .setVideoThumbnailListener(null) //视频缩略图
            .setInjectLayoutResourceListener(null) //自定义布局
            .setSelectionMode(if (single) SelectModeConfig.SINGLE else SelectModeConfig.MULTIPLE) //单选
            .setLanguage(LanguageConfig.UNKNOWN_LANGUAGE)
            .setQuerySortOrder("") //排序
            .setOutputCameraDir(getSandboxPath())
            .setOutputAudioDir(getSandboxPath())
            .setQuerySandboxDir(getSandboxPath())
            .isDisplayTimeAxis(true)
            .isOnlyObtainSandboxDir(false)
            .isPageStrategy(true)
            .isOriginalControl(false)
            .isDisplayCamera(true)
            .isOpenClickSound(false)
            .setSkipCropMimeType("")
            .isFastSlidingSelect(true) //.setOutputCameraImageFileName("luck.jpeg")
            //.setOutputCameraVideoFileName("luck.mp4")
            .isWithSelectVideoImage(true)
            .isPreviewFullScreenMode(true)
            .isPreviewZoomEffect(true)
            .isPreviewImage(true)
            .isPreviewVideo(true)
            .isPreviewAudio(true) //.setQueryOnlyMimeType(PictureMimeType.ofGIF())
            .isMaxSelectEnabledMask(true)
            .isDirectReturnSingle(false)
            .setMaxSelectNum(maxSelectNum)
            .setMaxVideoSelectNum(maxVideoSelectNum)
            .setRecyclerAnimationMode(AnimationType.DEFAULT_ANIMATION)
            .isGif(false)
            .setSelectedData(java.util.ArrayList())
        selectionModel.forResult(launcher)
    }

    /**
     * 相册选择通配
     *
     * @param single
     */
    open fun selectFromAlbumVideo(
        single: Boolean,
        launcher: ActivityResultLauncher<Intent?>?,
        maxSelectNum: Int
    ) {
        if(launcher == null) return

        // 进入相册
        val selectionModel = PictureSelector.create(this)
            .openGallery(SelectMimeType.ofImage()) // 全部.PictureMimeType.ofAll()、图片.ofImage()、视频.ofVideo()、音频.ofAudio()
            .setSelectorUIStyle(selectorStyle)
            .setImageEngine(GlideEngine.createGlideEngine())
            .setCropEngine(ImageFileCropEngine()) //                .setCompressEngine(new ImageFileCompressEngine())//压缩
            .setSandboxFileEngine(MeSandboxFileEngine())
            .setCameraInterceptListener(null) //自定义相机
            .setRecordAudioInterceptListener(null) //录音
            .setSelectLimitTipsListener(MeOnSelectLimitTipsListener())
            .setEditMediaInterceptListener(
                MeOnMediaEditInterceptListener(
                    getSandboxPath(),
                    buildOptions()
                )
            )
            .setPermissionDescriptionListener(null) //权限说明
            .setPreviewInterceptListener(null) //自定义预览
            .setPermissionDeniedListener(MeOnPermissionDeniedListener())
            .setAddBitmapWatermarkListener(null) //水印
            .setVideoThumbnailListener(null) //视频缩略图
            .setInjectLayoutResourceListener(null) //自定义布局
            .setSelectionMode(if (single) SelectModeConfig.SINGLE else SelectModeConfig.MULTIPLE) //单选
            .setLanguage(LanguageConfig.UNKNOWN_LANGUAGE)
            .setQuerySortOrder("") //排序
            .setOutputCameraDir(getSandboxPath())
            .setOutputAudioDir(getSandboxPath())
            .setQuerySandboxDir(getSandboxPath())
            .isDisplayTimeAxis(true)//
            .isOnlyObtainSandboxDir(false)//
            .isPageStrategy(true)//
            .isOriginalControl(false)//
            .isDisplayCamera(false)//
            .isOpenClickSound(false)//
            .setSkipCropMimeType("")//
            .isFastSlidingSelect(true) //
            //.setOutputCameraVideoFileName("luck.mp4")
            .isWithSelectVideoImage(false)//是否支持视频图片同选
            .isPreviewFullScreenMode(true)//
            .isPreviewZoomEffect(true)//
            .isPreviewImage(false)//
            .isPreviewVideo(true)//
            .isPreviewAudio(false) //是否支持音频预览
            .isMaxSelectEnabledMask(true)//
            .isDirectReturnSingle(false)//单选时是否立即返回
            .setMaxSelectNum(maxSelectNum)
            .setMaxVideoSelectNum(1)
            .setRecyclerAnimationMode(-1)
            .isGif(false)
            .setSelectedData(java.util.ArrayList<LocalMedia>())
        selectionModel.forResult(launcher)
    }

}